package cn.mazexal.examapi.utils;


import cn.mazexal.examapi.common.models.BizException;
import cn.mazexal.examapi.common.models.CustomerError;
import cn.mazexal.examapi.models.enums.UnitEnum;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author: Mazexal
 * Date: 2024/12/10
 */
public class DateUtils {

    public static final Long WEEK_TIME = 604800000L;

    public static final Long HOUR_TIME = 3600000L;

    public static final Long DAY_TIME = 86400000L;

    public static final Long MINUTE_TIME = 60000L;

    public static final Long MONTH_TIME = 2592000000L;

    public static final Long YEAR_TIME = 31536000000L;

    private static final SimpleDateFormat hourFormat = new SimpleDateFormat("yyyyMMddHH");

    private static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyyMMdd");

    private static final SimpleDateFormat monthFormat = new SimpleDateFormat("yyyyMM");

    private static final SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");

    private static final SimpleDateFormat standardFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 日期转LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate dateToLocalDate(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 获取一个星期的第一天时间戳
     *
     * @param date
     * @return
     */
    public static long getLastWeekStart(Date date) {
        LocalDate today = dateToLocalDate(date);
        DayOfWeek dow = today.getDayOfWeek();
        int todayValue = dow.getValue();
        int monday = DayOfWeek.MONDAY.getValue();
        int diff = todayValue - monday;
        LocalDate day = today.minusDays(diff + 7);
        LocalDateTime ldt = LocalDateTime.of(day.getYear(), day.getMonth(), day.getDayOfMonth(), 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }


    /**
     * 获取一个星期的最后一天最后时间戳
     *
     * @param date
     * @return
     */
    public static long getLastWeekEnd(Date date) {
        return getLastWeekStart(date) + WEEK_TIME - 1;
    }

    /**
     * 获取删一个小时的开始时间戳
     *
     * @param date
     * @return
     */
    public static Long getLastHourBegin(Date date) {
        Calendar calendar = Calendar.getInstance();
        /* HOUR_OF_DAY 指示一天中的小时 */
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, -1);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime().getTime();
    }

    public static Long getCurrentHourBegin(Date date) {
        Calendar calendar = Calendar.getInstance();
        /* HOUR_OF_DAY 指示一天中的小时 */
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime().getTime();
    }


    public static Long getLastDayBegin(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusDays(1);
        LocalDateTime ldt = LocalDateTime.of(last.getYear(), last.getMonth(), last.getDayOfMonth(), 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static Long getCurrentDayBegin(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDateTime ldt = LocalDateTime.of(today.getYear(), today.getMonth(), today.getDayOfMonth(), 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static Long getLastDayEnd(Date date) {
        return getLastDayBegin(date) + DAY_TIME - 1;
    }

    /**
     * 获取上一个小时的结束时间戳
     *
     * @param date
     * @return
     */
    public static Long getLastHourEnd(Date date) {
        return getLastHourBegin(date) + HOUR_TIME - 1;
    }

    /**
     * 获取上月第一天
     *
     * @param date
     * @return
     */
    public static Long getLastMonthBegin(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusMonths(1);
        LocalDateTime ldt = LocalDateTime.of(last.getYear(), last.getMonth(), 1, 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static Long getCurrentMonthBegin(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDateTime ldt = LocalDateTime.of(today.getYear(), today.getMonth(), 1, 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    /**
     * 获取上月最后一天最后一秒
     *
     * @param date
     * @return
     */
    public static long getLastMonthEnd(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusMonths(1);
        LocalDate lastDay = last.with(TemporalAdjusters.lastDayOfMonth());
        LocalDateTime ldt = LocalDateTime.of(lastDay.getYear(), lastDay.getMonth(), lastDay.getDayOfMonth(), 23, 59,
                59, 999999999);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static long getLastYearBegin(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusYears(1);
        LocalDateTime ldt = LocalDateTime.of(last.getYear(), 1, 1, 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static long getCurrentYearBegin(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDateTime ldt = LocalDateTime.of(today.getYear(), 1, 1, 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static long getLastYearEnd(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusYears(1);
        LocalDateTime ldt = LocalDateTime.of(last.getYear(), 12, 31, 23, 59, 59, 999999999);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static Integer getTimeShortHour(Long lastHourBeginTime) {
        return Integer.valueOf(hourFormat.format(new Date(lastHourBeginTime)));
    }

    public static Integer getTimeShortDay(Long lastDayBeginTime) {
        return Integer.valueOf(dayFormat.format(new Date(lastDayBeginTime)));
    }

    public static Integer getTimeShortMonth(Long lastDayBeginTime) {
        return Integer.valueOf(monthFormat.format(new Date(lastDayBeginTime)));
    }

    public static Integer getTimeShortYear(Long lastYearBeginTime) {
        return Integer.valueOf(yearFormat.format(new Date(lastYearBeginTime)));
    }


    public static Long getCurrentMonthEnd(Long timeStamp) {
        LocalDate today = dateToLocalDate(new Date(timeStamp)).with(TemporalAdjusters.lastDayOfMonth());
        LocalDateTime ldt = LocalDateTime.of(today.getYear(), today.getMonth(), today.getDayOfMonth(), 23, 59,
                59, 999999999);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static Long getCurrentYearEnd(Long timeStamp) {
        LocalDate today = dateToLocalDate(new Date(timeStamp));
        LocalDateTime ldt = LocalDateTime.of(today.getYear(), 12, 31, 23, 59, 59, 999999999);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    public static String formatTime(Long aLong) {
        return standardFormat.format(new Date(aLong));
    }

    public static Long calcDuration(Integer duration, Integer unit) {
        Long res;
        UnitEnum unitEnum = UnitEnum.toEnum(unit);
        switch (unitEnum) {
            case MINUTE:
                res = duration * MINUTE_TIME;
                break;
            case HOUR:
                res = duration * HOUR_TIME;
                break;
            case DAY:
                res = duration * DAY_TIME;
                break;
            case WEEK:
                res = duration * WEEK_TIME;
                break;
            case MONTH:
                res = duration * MONTH_TIME;
                break;
            case YEAR:
                res = duration * YEAR_TIME;
                break;
            default:
                throw new BizException(new CustomerError("500", "不支持的时长单位"));
        }
        return res;
    }
}
